package com.lost.octopus.es.processor.mq.consumer.capture;

import com.lost.octopus.es.processor.constant.enums.OperationType;
import com.lost.octopus.es.processor.mq.consumer.dto.ChangeDataCaptureInfo;
import com.lost.octopus.es.processor.mq.consumer.dto.SinkDeal;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 数据捕获,忽略相关的处理管理
 * @author zhangbh
 * @date 2025/5/13 14:33
 */
@Log4j2
@Component
public class DataCaptureIgnoreManager {


    /**
     * 忽略字段,格式:[T_DZ=BZ,CZRY;T_DZ_LD=XQBH,XXBH]
     */
    @Value("${es.exclude-field-list}")
    private String excludeFieldList;

    /**
     * 忽略字段:key=table,value=fieldStr
     */
    @Getter
    private Map<String, Set<String>> excludeFieldMap = new HashMap<>();

    private boolean load = false;


    @EventListener(ApplicationStartedEvent.class)
    public void init() {
        if (load) {
            return;
        }
        loadFieldList(excludeFieldList);
        load = true;
    }

    boolean ignoreChildSink(ChangeDataCaptureInfo data, SinkDeal info) {
        boolean ignoreField = false;
        String type = data.getType();
        boolean isUpdate = OperationType.UPDATE.eq(type);
        // 非更新就不走忽略
        if (!isUpdate) {
            return false;
        }
        Set<String> excludeFieldList = excludeFieldMap.get(data.getTableName());
        if (CollectionUtils.isEmpty(excludeFieldList)) {
            log.debug("table {} 没有忽略规则, 通知", data.getTableName());
            return false;
        }
        List<String> changeFields = excludeReg(data.getChangeFields(), excludeFieldList);
        boolean ignore = excludeFieldList.containsAll(changeFields);
        if (ignore) {
            log.info("捕获规则 sinkDeal {} 忽略主表变更，不处理子规则 =============== ignoreField {} changeFields {}",
                info.getDesc(), excludeFieldList, data.getChangeFields());
        }
        return ignore;
    }

    List<String> excludeReg(List<String> changeFields, Set<String> excludeFieldList) {
        // 排除掉正则忽略的字段
        List<String> result = new ArrayList<>(changeFields);
        for (String excludeField : excludeFieldList) {
            if (excludeField.contains(".*")) {
                result.removeIf(changeField -> {
                    boolean matches = changeField.matches(excludeField);
                    if (matches) {
                        log.debug("【es数据变更信息流】正则匹配到排除字段 excludeField={} changeField={}", excludeField, changeField);
                    }
                    return matches;
                });
            }
        }
        return result;
    }

    /**
     * 加载字段配置
     * 格式：T_DZ=ZHHSSJ,ZPID;T_RK_RFGL=ZHHSSJ;
     */
    void loadFieldList(String fieldStr) {
        if (StringUtils.isBlank(fieldStr)) {
            return;
        }
        Map<String, Set<String>> ignoreMap = new HashMap<>();
        try {
            for (String tableConfig : fieldStr.split(";")) {
                String configTable = tableConfig.split("=")[0];
                String configField = tableConfig.split("=")[1];
                // 加入字段
                Set<String> fieldList = new HashSet<>(Arrays.asList(configField.split(",")));
                if (CollectionUtils.isNotEmpty(fieldList)) {
                    log.info("读取到监控配置 tableName = [{}] fieldList = [{}]", configTable, fieldList);
                }
                excludeFieldMap.putIfAbsent(configTable, fieldList);
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("字段配置格式错误,数据：" + fieldStr + "格式：T_DZ=ZHHSSJ,ZPID;T_RK_RFGL=ZHHSSJ");
        }
    }

}
